﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace QQ2564874169.RelationalSql
{
    public static class RelationalSqlExts
    {
        public static int Update<T>(this IDbExecute execute, T model, int? timeout = null) where T : new()
        {
            var idp = typeof(T).GetProperty("id", BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
            if (idp == null)
                throw new NotSupportedException("实体中没有名为ID的属性。");

            var id = idp.GetValue(model);
            if (id == null)
                throw new ArgumentException("ID不能为空。");

            var whereModel = Activator.CreateInstance<T>();
            idp.SetValue(whereModel, id);
            var setModel = Activator.CreateInstance<T>();
            foreach (var p in typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public))
            {
                var v = p.GetValue(model);
                if (v != null && p.Name != idp.Name)
                    p.SetValue(setModel, v);
            }
            return execute.Update(setModel, whereModel, timeout);
        }

        public static int SetNull<T>(this IDbExecute execute, T model, int? timeout = null)
        {
            var p = typeof(T).GetProperty("id", BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
            if (p == null)
                throw new NotSupportedException("实体中没有名为ID的属性。");

            var id = p.GetValue(model);
            if (id == null)
                throw new ArgumentException("ID不能为空。");

            var whereModel = Activator.CreateInstance<T>();
            p.SetValue(whereModel, id);
            p.SetValue(model, p.PropertyType.GetDefaultValue());

            return execute.SetNull(model, whereModel, timeout);
        }

        public static T GetForUpdate<T>(this IDbEntityQuery query, T whereModel, int? timeout = null)
        {
            return query.Get(whereModel, true, timeout);
        }

        public static IEnumerable<T> GetsForUpdate<T>(this IDbEntityQuery query, T whereModel, int? timeout = null)
        {
            return query.Gets(whereModel, true, null, timeout);
        }

        public static DataSort ToAsc<T>(this DataSort model, params Expression<Func<T, object>>[] expressions)
        {
            foreach (var item in expressions)
            {
                var member = item.Body as MemberExpression;
                var unary = item.Body as UnaryExpression;
                member = member ?? unary?.Operand as MemberExpression;
                if (member != null)
                    model.Sorts.Add(member.Member.Name);
            }
            return model;
        }

        public static DataSort ToDesc<T>(this DataSort model, params Expression<Func<T, object>>[] expressions)
        {
            foreach (var item in expressions)
            {
                var member = item.Body as MemberExpression;
                var unary = item.Body as UnaryExpression;
                member = member ?? unary?.Operand as MemberExpression;
                if (member != null)
                    model.Sorts.Add("!" + member.Member.Name);
            }
            return model;
        }

        public static PageSort ToAsc<T>(this PageSort model, params Expression<Func<T, object>>[] expressions)
        {
            foreach (var item in expressions)
            {
                var member = item.Body as MemberExpression;
                var unary = item.Body as UnaryExpression;
                member = member ?? unary?.Operand as MemberExpression;
                if (member != null)
                    model.Sorts.Add(member.Member.Name);
            }
            return model;
        }

        public static PageSort ToDesc<T>(this PageSort model, params Expression<Func<T, object>>[] expressions)
        {
            foreach (var item in expressions)
            {
                var member = item.Body as MemberExpression;
                var unary = item.Body as UnaryExpression;
                member = member ?? unary?.Operand as MemberExpression;
                if (member != null)
                    model.Sorts.Add("!" + member.Member.Name);
            }
            return model;
        }

        public static string ToMssql(this DataSort model)
        {
            if (model == null || model.Sorts.Count < 1)
                return null;

            var sql = "ORDER BY";

            foreach (var item in model.Sorts)
            {
                if (item.Contains(" "))
                    throw new ArgumentException("mssql的排序格式是name或者!name，!表示倒序。");
                if (item.StartsWith("!"))
                {
                    sql += " " + item.Substring(1) + " DESC";
                }
                else
                {
                    sql += " " + item + " ASC";
                }
            }
            return sql;
        }

        public static PageResult<T> Pager<T>(this IDbSqlQuery query, string sql, PageSort pageset,
            object param = null, bool isProc = false, int? timeout = null)
        {
            var countsql = pageset.ToCountSql(sql);
            var datasql = pageset.ToDataSql(sql);
            sql = countsql + " " + datasql;

            using (var reader = query.QueryMultiple(sql, param, isProc, timeout))
            {
                var sum = reader.Read<int>().FirstOrDefault();
                var data = reader.Read<T>();
                return new PageResult<T>(pageset, sum, data);
            }
        }
    }
}
